import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, DataSource, In } from "typeorm";
import { User } from "./user.entity";
import { Profile } from "./profile.entity";
import { Roles } from "../roles/roles.entity";
import { LogsService } from "../logs/logs.service";
import { LogLevel } from "../logs/logs.entity";
import { CreateUserDto, UserQueryDto, UserResponseDto, UpdateUserDto } from "./dto";
import { Gender } from "../enum/gender.enum";
import type { PaginatedResponse } from "../../types/api-response.interface";
import { isInEnum } from "../utils/tool";
import { createPaginatedErrorResponse, createPaginatedSuccessResponse } from "../utils/response";
import * as argon2 from "argon2";

/**
 * 用户服务 - 处理用户相关的业务逻辑
 */
@Injectable()
export class UserService {
  // 注入User、Profile、Roles实体的Repository，用于数据库操作
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    private readonly logsService: LogsService,
    private dataSource: DataSource,
  ) {}

  /**
   * 查询所有用户（支持分页、搜索、筛选）
   */
  async findAll(queryDto: UserQueryDto = {}): Promise<PaginatedResponse<UserResponseDto>> {
    try {
      const { page = 1, pageSize = 10, search, gender, roleId } = queryDto;

      // 参数验证
      if (page <= 0) {
        return createPaginatedErrorResponse("页码必须大于0", page, pageSize);
      }

      if (pageSize <= 0 || pageSize > 100) {
        return createPaginatedErrorResponse("每页数量必须在1-100之间", page, pageSize);
      }

      // 创建查询构建器
      const queryBuilder = this.userRepository
        .createQueryBuilder("user")
        .leftJoinAndSelect("user.profile", "profile")
        .leftJoinAndSelect("user.roles", "roles")
        .select([
          "user.id",
          "user.username",
          "user.createdAt",
          "profile.id",
          "profile.gender",
          "profile.photo",
          "profile.email",
          "profile.address",
          "roles.id",
          "roles.name",
        ]);

      // 搜索条件：用户名或邮箱
      if (search && search.trim()) {
        queryBuilder.andWhere(
          "(user.username LIKE :search OR (profile.email IS NOT NULL AND profile.email LIKE :search))",
          {
            search: `%${search.trim()}%`,
          },
        );
      }

      // 性别筛选
      if (isInEnum(gender, Gender)) {
        queryBuilder.andWhere("profile.gender = :gender", { gender });
      }
      // 角色筛选
      if (roleId && roleId > 0) {
        queryBuilder.innerJoin("user.roles", "role", "role.id = :roleId", { roleId });
      }

      // 排序
      queryBuilder.orderBy("user.createdAt", "DESC");

      // 先获取总数，用于页码范围验证
      const total = await queryBuilder.getCount();
      const totalPages = Math.ceil(total / pageSize);

      // 页码范围验证
      if (total > 0 && page > totalPages) {
        return createPaginatedErrorResponse(
          `请求的页码 ${page} 超出数据范围，当前共 ${totalPages} 页数据`,
          page,
          pageSize,
          total,
          totalPages,
        );
      }

      // 如果没有数据
      if (total === 0) {
        const hasFilters = search || isInEnum(gender, Gender) || (roleId && roleId > 0);
        const noDataMessage = hasFilters ? "未找到符合条件的用户数据" : "暂无用户数据";
        return createPaginatedSuccessResponse([], 0, page, pageSize, noDataMessage);
      }

      // 分页查询
      const offset = (page - 1) * pageSize;
      queryBuilder.skip(offset).take(pageSize);

      // 执行查询
      const users = await queryBuilder.getMany();

      // 计算总页数（重新计算确保一致性）
      const finalTotalPages = Math.ceil(total / pageSize);

      // 记录操作日志
      await this.logsService.createSystemLog(
        `查询用户列表，页码: ${page}/${finalTotalPages}，每页: ${pageSize}，搜索: ${search || "无"}，性别筛选: ${isInEnum(gender, Gender) ? Gender[gender as Gender] : "无"}，角色筛选: ${roleId && roleId > 0 ? `角色ID ${roleId}` : "无"}，共找到 ${total} 个用户`,
        LogLevel.INFO,
        "UserService.findAll",
      );

      return createPaginatedSuccessResponse(users as UserResponseDto[], total, page, pageSize, "查询成功");
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.findAll");
      throw new Error(`查询用户列表失败: ${error.message}`);
    }
  }

  /**
   * 根据用户名查找用户
   * @param username 用户名
   */
  async find(username: string) {
    try {
      if (!username || username.trim() === "") {
        throw new Error("用户名不能为空");
      }

      const user = await this.userRepository.findOne({
        where: {
          username: username.trim(),
        },
        relations: ["profile", "roles", "roles.menus"],
      });

      // 记录操作日志
      await this.logsService.createSystemLog(
        `根据用户名查找用户: ${username.trim()}，${user ? "找到用户" : "用户不存在"}`,
        LogLevel.INFO,
        "UserService.find",
      );

      return user;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.find", undefined, { username });

      if (error.message.includes("用户名不能为空")) {
        throw error;
      }
      throw new Error(`根据用户名查找用户失败: ${error.message}`);
    }
  }

  /**
   * 根据用户id查找用户
   * @param id 用户id
   */
  async findOne(id: number) {
    try {
      if (!id || id <= 0) {
        throw new Error("用户ID必须是正整数");
      }

      const user = await this.userRepository.findOne({
        where: { id },
        relations: ["profile", "roles"],
      });

      if (!user) {
        throw new Error(`用户 ID ${id} 不存在`);
      }

      // 记录操作日志
      await this.logsService.createSystemLog(
        `根据ID查找用户: ${id}，用户名: ${user.username}`,
        LogLevel.INFO,
        "UserService.findOne",
        { userId: id },
      );

      return user;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.findOne", undefined, { userId: id });

      if (error.message.includes("用户ID必须是正整数") || error.message.includes("不存在")) {
        throw error;
      }
      throw new Error(`查找用户失败: ${error.message}`);
    }
  }

  /**
   * 根据用户邮箱查找用户
   * @param email 用户邮箱
   */
  async findByEmail(email: string) {
    try {
      if (!email) {
        throw new Error("邮箱不能为空");
      }
      const user = await this.userRepository.findOne({
        where: { profile: { email } },
        relations: ["profile", "roles"],
      });

      if (!user) {
        throw new Error(`用户 邮箱 ${email} 不存在`);
      }

      // 记录操作日志
      await this.logsService.createSystemLog(
        `根据email查找用户: ${email}，用户名: ${user.username}`,
        LogLevel.INFO,
        "UserService.findByEmail",
        { email },
      );

      return user;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.findByEmail", undefined, { email });
    }
  }

  /**
   * 创建新用户（包含profile信息和角色分配）
   * @param userCreateDto 用户创建数据
   */
  async create(userCreateDto: CreateUserDto) {
    // 使用数据库事务确保数据一致性
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 1. 参数验证
      if (!userCreateDto.username || !userCreateDto.password) {
        throw new Error("用户名和密码不能为空");
      }

      if (!userCreateDto.profile) {
        throw new Error("用户档案信息不能为空");
      }

      if (!userCreateDto.profile.email) {
        throw new Error("邮箱不能为空");
      }

      // 2. 检查用户名是否已存在
      const existingUser = await queryRunner.manager.findOne(User, {
        where: { username: userCreateDto.username },
      });

      if (existingUser) {
        throw new Error(`用户名 "${userCreateDto.username}" 已存在`);
      }

      // 3. 检查邮箱是否已存在
      const existingProfile = await queryRunner.manager.findOne(Profile, {
        where: { email: userCreateDto.profile.email },
      });

      if (existingProfile) {
        throw new Error(`邮箱 "${userCreateDto.profile.email}" 已存在`);
      }

      // 4. 验证角色ID是否存在
      let rolesToAssign: Roles[] = [];
      if (userCreateDto.roles && userCreateDto.roles.length > 0) {
        rolesToAssign = await queryRunner.manager.find(Roles, {
          where: {
            id: In(userCreateDto.roles),
          },
        });

        if (rolesToAssign.length !== userCreateDto.roles.length) {
          const foundRoleIds = rolesToAssign.map((role) => role.id);
          const missingRoleIds = userCreateDto.roles.filter((id) => !foundRoleIds.includes(id));
          throw new Error(`角色ID不存在: ${missingRoleIds.join(", ")}`);
        }
      }

      const secretPassword = await argon2.hash(userCreateDto.password);

      // 5. 创建用户基本信息
      const newUser = queryRunner.manager.create(User, {
        username: userCreateDto.username,
        password: secretPassword,
      });
      const savedUser = await queryRunner.manager.save(User, newUser);

      // 6. 创建用户档案信息
      const newProfile = queryRunner.manager.create(Profile, {
        gender: userCreateDto.profile.gender,
        email: userCreateDto.profile.email,
        address: userCreateDto.profile.address,
        photo: userCreateDto.profile.photo,
        user: savedUser,
      });
      const savedProfile = await queryRunner.manager.save(Profile, newProfile);

      // 7. 分配角色（如果有）
      if (rolesToAssign.length > 0) {
        savedUser.roles = rolesToAssign;
        await queryRunner.manager.save(User, savedUser);
      }

      // 8. 提交事务
      await queryRunner.commitTransaction();

      // 9. 记录操作日志
      await this.logsService.createSystemLog(
        `创建新用户成功: ${savedUser.username} (ID: ${savedUser.id})，包含档案信息，分配角色: ${rolesToAssign.map((r) => r.name).join(", ") || "无"}`,
        LogLevel.INFO,
        "UserService.create",
        {
          newUserId: savedUser.id,
          username: savedUser.username,
          profileId: savedProfile.id,
          assignedRoles: rolesToAssign.map((r) => ({ id: r.id, name: r.name })),
        },
      );

      // 10. 返回完整的用户信息（包含关联数据）
      const createdUser = await this.userRepository.findOne({
        where: { id: savedUser.id },
        relations: ["profile", "roles"],
      });

      return createdUser;
    } catch (error) {
      // 回滚事务
      await queryRunner.rollbackTransaction();

      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.create", undefined, {
        username: userCreateDto.username,
        email: userCreateDto.profile?.email,
        roles: userCreateDto.roles,
      });

      if (
        error.message.includes("不能为空") ||
        error.message.includes("已存在") ||
        error.message.includes("角色ID不存在")
      ) {
        throw error;
      }

      // 处理数据库唯一约束错误
      if (error.code === "ER_DUP_ENTRY") {
        if (error.message.includes("username")) {
          throw new Error(`用户名 "${userCreateDto.username}" 已存在`);
        }
        if (error.message.includes("email")) {
          throw new Error(`邮箱 "${userCreateDto.profile?.email}" 已存在`);
        }
        throw new Error("数据重复，创建用户失败");
      }

      throw new Error(`创建用户失败: ${error.message}`);
    } finally {
      // 释放数据库连接
      await queryRunner.release();
    }
  }

  /**
   * 更新用户信息（支持更新基本信息、档案信息和角色分配）
   * @param id 用户ID
   * @param updateDto 更新的用户信息
   */
  async update(id: number, updateDto: UpdateUserDto) {
    // 使用数据库事务确保数据一致性
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 1. 参数验证
      if (!id || id <= 0) {
        throw new Error("用户ID必须是正整数");
      }

      // 2. 检查用户是否存在，并获取完整信息
      const existingUser = await queryRunner.manager.findOne(User, {
        where: { id },
        relations: ["profile", "roles"],
      });

      if (!existingUser) {
        throw new Error(`用户 ID ${id} 不存在`);
      }

      const updateOperations: string[] = [];

      // 3. 更新用户基本信息
      if (updateDto.username || updateDto.password) {
        const userUpdateData: { username?: string; password?: string } = {};

        // 检查用户名是否需要更新且不重复
        if (updateDto.username && updateDto.username !== existingUser.username) {
          const duplicateUser = await queryRunner.manager.findOne(User, {
            where: { username: updateDto.username },
          });

          if (duplicateUser) {
            throw new Error(`用户名 "${updateDto.username}" 已存在`);
          }
          userUpdateData.username = updateDto.username;
          updateOperations.push("用户名");
        }

        // 更新密码
        if (updateDto.password) {
          userUpdateData.password = updateDto.password;
          updateOperations.push("密码");
        }

        // 执行用户基本信息更新
        if (Object.keys(userUpdateData).length > 0) {
          await queryRunner.manager.update(User, id, userUpdateData);
        }
      }

      // 4. 更新用户档案信息
      if (updateDto.profile) {
        const profileData = updateDto.profile;

        // 检查邮箱是否需要更新且不重复
        if (profileData.email && profileData.email !== existingUser.profile?.email) {
          const duplicateProfile = await queryRunner.manager.findOne(Profile, {
            where: { email: profileData.email },
          });

          if (duplicateProfile && duplicateProfile.user.id !== id) {
            throw new Error(`邮箱 "${profileData.email}" 已存在`);
          }
        }

        if (existingUser.profile) {
          // 更新现有档案
          const profileUpdateData: {
            email?: string;
            gender?: Gender;
            address?: string;
            photo?: string;
          } = {};

          if (profileData.email !== undefined) profileUpdateData.email = profileData.email;
          if (profileData.gender !== undefined) profileUpdateData.gender = profileData.gender;
          if (profileData.address !== undefined) profileUpdateData.address = profileData.address;
          if (profileData.photo !== undefined) profileUpdateData.photo = profileData.photo;

          if (Object.keys(profileUpdateData).length > 0) {
            await queryRunner.manager.update(Profile, existingUser.profile.id, profileUpdateData);
            updateOperations.push("档案信息");
          }
        } else {
          // 创建新档案 - 确保提供所有必需字段
          const newProfileData = {
            gender: profileData.gender || Gender.FEMALE, // 提供默认性别
            email: profileData.email || "", // 邮箱必需，如果未提供则使用空字符串
            address: profileData.address || "", // 地址必需，如果未提供则使用空字符串
            photo: profileData.photo || "", // 头像必需，如果未提供则使用空字符串
            user: existingUser,
          };

          // 验证必需字段
          if (!newProfileData.email) {
            throw new Error("创建用户档案时邮箱不能为空");
          }

          const newProfile = queryRunner.manager.create(Profile, newProfileData);
          await queryRunner.manager.save(Profile, newProfile);
          updateOperations.push("创建档案信息");
        }
      }

      // 5. 更新角色分配
      if (updateDto.roles !== undefined) {
        let rolesToAssign: Roles[] = [];

        if (updateDto.roles && updateDto.roles.length > 0) {
          // 验证角色ID是否存在
          rolesToAssign = await queryRunner.manager.find(Roles, {
            where: {
              id: In(updateDto.roles),
            },
          });

          if (rolesToAssign.length !== updateDto.roles.length) {
            const foundRoleIds = rolesToAssign.map((role) => role.id);
            const missingRoleIds = updateDto.roles.filter((id) => !foundRoleIds.includes(id));
            throw new Error(`角色ID不存在: ${missingRoleIds.join(", ")}`);
          }
        }

        // 更新用户角色关联
        const userWithRoles = await queryRunner.manager.findOne(User, {
          where: { id },
          relations: ["roles"],
        });

        if (userWithRoles) {
          userWithRoles.roles = rolesToAssign;
          await queryRunner.manager.save(User, userWithRoles);
          updateOperations.push(`角色分配 (${rolesToAssign.map((r) => r.name).join(", ") || "清空"})`);
        }
      }

      // 6. 提交事务
      await queryRunner.commitTransaction();

      // 7. 记录操作日志
      await this.logsService.createSystemLog(
        `更新用户信息成功: ${existingUser.username} (ID: ${id})，更新内容: ${updateOperations.join(", ") || "无变更"}`,
        LogLevel.INFO,
        "UserService.update",
        {
          userId: id,
          username: existingUser.username,
          updateOperations,
          newUsername: updateDto.username,
          newEmail: updateDto.profile?.email,
          assignedRoles: updateDto.roles,
        },
      );

      // 8. 返回更新后的完整用户信息
      const updatedUser = await this.userRepository.findOne({
        where: { id },
        relations: ["profile", "roles"],
      });

      return updatedUser;
    } catch (error) {
      // 回滚事务
      await queryRunner.rollbackTransaction();

      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.update", undefined, {
        userId: id,
        username: updateDto.username,
        email: updateDto.profile?.email,
        roles: updateDto.roles,
      });

      if (
        error.message.includes("用户ID必须是正整数") ||
        error.message.includes("不存在") ||
        error.message.includes("已存在") ||
        error.message.includes("角色ID不存在")
      ) {
        throw error;
      }

      // 处理数据库唯一约束错误
      if (error.code === "ER_DUP_ENTRY") {
        if (error.message.includes("username")) {
          throw new Error(`用户名已存在，无法更新`);
        }
        if (error.message.includes("email")) {
          throw new Error(`邮箱已存在，无法更新`);
        }
        throw new Error("数据重复，更新用户失败");
      }

      throw new Error(`更新用户失败: ${error.message}`);
    } finally {
      // 释放数据库连接
      await queryRunner.release();
    }
  }

  /**
   * 删除用户
   * @param id 用户ID
   */
  async remove(id: number) {
    // 参数验证
    if (!id || id <= 0) {
      throw new Error("用户ID必须是正整数");
    }
    // 使用数据库事务确保数据一致性
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 先获取用户信息用于日志记录（包含关联数据）
      const existingUser = await queryRunner.manager.findOne(User, {
        where: { id },
        relations: ["profile", "roles"],
      });

      if (!existingUser) {
        throw new Error(`用户 ID ${id} 不存在`);
      }

      // 记录删除前的信息用于日志
      const deletionInfo = {
        userId: id,
        username: existingUser.username,
        hasProfile: !!existingUser.profile,
        roleCount: existingUser.roles?.length || 0,
        roleNames: existingUser.roles?.map((role) => role.name) || [],
      };

      // 1. 删除用户角色关联（多对多中间表）
      if (existingUser.roles && existingUser.roles.length > 0) {
        await queryRunner.manager
          .createQueryBuilder()
          .delete()
          .from("users_roles")
          .where("userId = :userId", { userId: id })
          .execute();
      }

      // 2. 删除用户档案（一对一关系）
      if (existingUser.profile) {
        await queryRunner.manager.delete(Profile, { user: { id } });
      }

      // 3. 删除用户记录
      // const result = await queryRunner.manager.delete(User, id);
      await queryRunner.manager.remove(existingUser);

      // 提交事务
      await queryRunner.commitTransaction();

      // 记录操作日志
      await this.logsService.createSystemLog(
        `删除用户成功: ${deletionInfo.username} (ID: ${id})`,
        LogLevel.WARN,
        "UserService.remove",
        {
          deletedUserId: id,
          deletedUsername: deletionInfo.username,
          deletedProfile: deletionInfo.hasProfile,
          deletedRoles: deletionInfo.roleNames,
          deletedRoleCount: deletionInfo.roleCount,
        },
      );

      return {
        // affected: result.affected,
        deletedUser: deletionInfo.username,
        deletedProfile: deletionInfo.hasProfile,
        deletedRoles: deletionInfo.roleCount,
      };
    } catch (error) {
      // 回滚事务
      await queryRunner.rollbackTransaction();

      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.remove", undefined, { userId: id });

      // 处理自定义错误
      if (error.message.includes("用户ID必须是正整数") || error.message.includes("不存在")) {
        throw error;
      }

      // 处理数据库错误
      if (error.code) {
        throw new Error(`删除用户失败，数据库错误: ${error.message}`);
      }

      throw new Error(`删除用户失败: ${error.message}`);
    } finally {
      // 释放查询运行器
      await queryRunner.release();
    }
  }

  /**
   * 查询用户档案
   * @param id 用户ID
   * @returns 包含档案信息的用户对象，如果用户不存在则返回null
   */
  async findProfile(id: number) {
    try {
      // 参数验证
      if (!id || id <= 0) {
        throw new Error("用户ID必须是正整数");
      }

      // 查询用户和档案信息
      const user = await this.userRepository.findOne({
        where: { id },
        relations: { profile: true },
      });

      if (!user) {
        throw new Error(`不存在用户 ID ${id} 的档案数据`);
      }

      // 记录操作日志
      await this.logsService.createSystemLog(
        `查询用户档案: ${user.username} (ID: ${id})，${user.profile ? "包含档案信息" : "无档案信息"}`,
        LogLevel.INFO,
        "UserService.findProfile",
        {
          userId: id,
          username: user.username,
          hasProfile: !!user.profile,
        },
      );

      return user;
    } catch (error) {
      // 记录错误日志
      await this.logsService.createErrorLog(error, "UserService.findProfile", undefined, { userId: id });

      if (error.message.includes("用户ID必须是正整数") || error.message.includes("不存在")) {
        throw error;
      }
      throw new Error(`查询用户档案失败: ${error.message}`);
    }
  }
}
